//
// Created by Criinal Nicole on 2021/5/10.
//

#ifndef GFD_PROPERTYVALUE_H
#define GFD_PROPERTYVALUE_H

#include <string>
#include <iostream>

enum PropertyValueType {
    INT,
    DOUBLE,
    STRING,
    UNDEFINED
};

class PropertyValue {
public:
    void *_propertyValuePointer{nullptr};
    PropertyValueType _propertyValueType{UNDEFINED};

    [[nodiscard]] inline
    int getValueInt() const { return *(static_cast<int *>(_propertyValuePointer)); }

    [[nodiscard]] inline
    double getValueDouble() const { return *(static_cast<double *>(_propertyValuePointer)); }

    [[nodiscard]] inline
    std::string getValueString() const { return *(static_cast<std::string *>(_propertyValuePointer)); }

//    定义两个属性相等，可以自定义
    bool operator==(const PropertyValue propertyValue) const {
        if (_propertyValueType == propertyValue._propertyValueType) {
            switch (_propertyValueType) {
                case PropertyValueType::INT:
                    return getValueInt() == propertyValue.getValueInt();
                case PropertyValueType::DOUBLE:
                    return getValueDouble() == propertyValue.getValueDouble();
                case PropertyValueType::STRING:
                    return getValueString() == propertyValue.getValueString();
                default:
                    return false;
            }
        }
        return false;
    }

//    定义两个属性的偏序关系
    friend bool operator<(PropertyValue a, PropertyValue b) {
        if (a._propertyValueType == UNDEFINED)return false;
        if (b._propertyValueType == UNDEFINED)return true;

        if (a._propertyValueType == b._propertyValueType) {
            switch (a._propertyValueType) {
                case PropertyValueType::INT:
                    return a.getValueInt() < b.getValueInt();
                case PropertyValueType::DOUBLE:
                    return a.getValueDouble() < b.getValueDouble();
                case PropertyValueType::STRING:
                    return a.getValueString() < b.getValueString();
                default:
                    return true;
            }
        }
        return a._propertyValueType < b._propertyValueType;
    }

    friend std::ostream &operator<<(std::ostream &out, PropertyValue propertyValue) {
        if (propertyValue._propertyValueType == PropertyValueType::INT) {
            out << propertyValue.getValueInt();
        } else if (propertyValue._propertyValueType == PropertyValueType::DOUBLE) {
            out << propertyValue.getValueDouble();
        } else if (propertyValue._propertyValueType == PropertyValueType::STRING) {
            out << propertyValue.getValueString();
        } else {
            out << "UNDEFINED";
        }
        return out;
    }
};


#endif //GFD_PROPERTYVALUE_H
